home *** CD-ROM | disk | FTP | other *** search
- (* Cross reference as above, but using a hash table instead
- of a binary tree to store the words encountered. *)
-
- (***************************************************************************************)
- (* MODULE crossref--This module is a cross reference generator. A file which is *)
- (* specified by the user is read and a cross reference table of all the words is built.*)
- (* A word consists of a letter and any combination of letters and digits thereafter *)
- (* until a separator, i.e. blanks, ends of lines, special characters, is read. Quotes *)
- (* and comments are ignored. The cross reference table is a hash table which stores *)
- (* the words and the number of the line on which the word appeared. When the table *)
- (* is generated, its contents are printed on the screen. This program is the MODULA-2 *)
- (* translation of the PASCAL program 11.2. *)
-
-
-
- MODULE crossref;
-
- FROM InOut IMPORT (* get necessary i/o files *)
- Read, WriteString, Write, WriteLn, WriteCard, OpenInput, CloseInput, Done;
- FROM Storage IMPORT (* get NEW procedure *)
- ALLOCATE;
-
- CONST ff = 14c; (* clear the screen constant *)
- eol = 36c; (* end of line constant *)
- quote = 42c; (* double quote mark *)
- wordlen = 10; (* maximum word length *)
- numperline = 8; (* no of line numbers per display line *)
- digpernum = 6; (* maximum number of digits per number *)
- maxline = 9999; (* maximum number of lines in file *)
- prime = 997; (* number of hash table entries *)
- blank = " "; (* blank character constant *)
- filetype = "TEXT"; (* default filename extension *)
-
- TYPE index = [0..prime]; (* range of hash table *)
- alfa = ARRAY[1..wordlen] OF CHAR; (* word string *)
- relation = (equal,less,greater); (* used for string comparisons *)
- itemref = POINTER TO item;
- word = RECORD (* hash table entries *)
- key : alfa; (* word found in text *)
- first, last: itemref; (* pointer to cross reference list *)
- follow : index (* hash number of next entry *)
- END;
- item = RECORD (* cross reference list *)
- lineno: [0..maxline]; (* line number word occurred on *)
- next : itemref (* pointer to next item in list *)
- END;
-
- VAR i : index; (* index to hash table *)
- top : index; (* current hash table entry *)
- idcntr : INTEGER; (* index to id array *)
- id : alfa; (* contains the current word *)
- free : alfa; (* blank word *)
- table : ARRAY [0..prime] OF word; (* hash table *)
- current : CARDINAL; (* current line number *)
- ch : CHAR; (* current character *)
- tablefull: BOOLEAN; (* flags if table gets full *)
-
-
- PROCEDURE compare(j,k:alfa):relation;
- (**************************************************************************************)
- (* This function compares the two strings j and k to see how they compare. If j = k *)
- (* then the value of equal is returned. If j < k then the value is less is returned *)
- (* and if j > k tthen the value greater is returned. *)
- (**************************************************************************************)
-
-
- VAR compvalue : relation; (* function value *)
- through : BOOLEAN; (* flags when through with loop *)
- i : INTEGER; (* array index *)
-
- BEGIN
- compvalue := equal; (* initializations *)
- i := 1;
- through := FALSE;
- WHILE (NOT through) & (i <= 10) DO (* compare the two strings *)
- IF CAP(j[i]) = CAP(k[i]) THEN
- INC(i)
- ELSE
- through := TRUE;
- IF CAP(j[i]) < CAP(k[i]) THEN
- compvalue := less
- ELSE
- compvalue := greater
- END
- END
- END;
- RETURN compvalue
- END compare;
-
-
-
- PROCEDURE search():BOOLEAN;
- (**************************************************************************************)
- (* This function searches the hash table to see if an entry for the current word *)
- (* already exists. This is done by calculating the hash value of the current word. *)
- (* If no entry exists at the hash value slot in the table, then an entry is created *)
- (* for that word and an item list created. If the entry already exists, then only a *)
- (* new item node is created and added to the item list. If the hash slot is already *)
- (* occupied by a different word, then the hash table is searched for an empty slot. *)
- (* If one is found, then it is filled in with the current word, etc. If no empty *)
- (* slot can be found, then a message is printed indicating table overflow and the *)
- (* procedure quits, returning the value of FALSE. *)
- (**************************************************************************************)
-
- VAR hash : CARDINAL; (* contains hash value *)
- addvalue : index; (* contains search increment value *)
- done : BOOLEAN; (* flags when finished *)
- full : BOOLEAN; (* flags if table is full *)
- x : itemref; (* pointer to current item list *)
- compvalue : relation; (* contains result of compare *)
-
-
- BEGIN
- full := FALSE; (* initialize *)
- hash := 0;
- done := FALSE;
- addvalue := 1;
- NEW(x); (* get a new item list node *)
- x^.lineno := current; (* fill in current line number *)
- x^.next := NIL; (* set next link to nil *)
- FOR i := 1 TO wordlen (* calculate hash value *)
- DO
- hash := (hash + ORD(id[i])) MOD prime
- END;
- REPEAT (* continue searching until done *)
- compvalue := compare(id, table[hash].key); (* compare id to key to see if equal *)
- IF compvalue = equal THEN (* if word entry already exists *)
- done := TRUE; (* flag to end loop *)
- table[hash].last^.next := x; (* link last item node to new node *)
- table[hash].last := x (* link table pointer to new last node*)
- ELSE
- compvalue := compare(free,table[hash].key);
- IF compvalue = equal THEN (* if no entry exists *)
- WITH table[hash] DO
- key := id; (* fill in current word *)
- first := x; (* link to item node *)
- last := x;
- follow := top (* fill in last hash table entry *)
- END;
- top := hash; (* set to current hash table entry *)
- done := TRUE
- ELSE (* collision occurred *)
- hash := hash + addvalue; (* incrmt hash to check next entry *)
- addvalue := addvalue + 2; (* increment displacement *)
- IF hash >= prime THEN (* if hash value greater than length *)
- hash := hash - prime (* reset hash value *)
- END;
- IF addvalue = prime THEN (* if table is full *)
- done := TRUE; (* flag that search is through *)
- full := TRUE; (* flag that table is full *)
- WriteString("Table Overflow");
- WriteLn
- END
- END
- END
- UNTIL done;
- RETURN full
- END search;
-
-
- PROCEDURE printtable;
- (**************************************************************************************)
- (* This procedure prints out the cross reference table. It lists each word and the *)
- (* line numbers on which that word occurred. Printtable has an internal procedure *)
- (* printword that handles printing the word and its line references. The cross *)
- (* reference table is printed out in alphabetical order. *)
- (**************************************************************************************)
-
- VAR hold : index; (* contains the current entry index *)
- least : index; (* contains index to least word *)
- move : index; (* used to search for least word *)
- compvalue : relation; (* contains compare result *)
-
- PROCEDURE printword(w: word);
-
-
- VAR numcnt: INTEGER; (* keeps track line nos on screen *)
- x : itemref; (* pointer to current item node *)
-
- BEGIN
- Write(blank);
- WriteString(w.key);
- x := w.first;
- numcnt := 0;
- REPEAT (* do until all line numbers printed *)
- IF numcnt = numperline THEN (* if need a new line for line nos *)
- numcnt := 0; (* reset counter *)
- WriteLn;
- Write(blank);
- WriteString(free)
- END;
- INC(numcnt);
- WriteCard(x^.lineno,digpernum); (* write the line number *)
- Write(blank); (* move to next item node *)
- x := x^.next
- UNTIL x = NIL;
- WriteLn;
- END printword;
-
- BEGIN
- hold := top; (* start at last entry to be added *)
- WHILE hold <> prime (* do for all of the table *)
- DO
- least := hold; (* initialize for alphabetic search *)
- move := table[hold].follow;
- WHILE move <> prime (* search table for least entry *)
- DO
- compvalue := compare(table[move].key,table[least].key);
- IF compvalue = less THEN
- least := move
- END;
- move := table[move].follow
- END;
- printword(table[least]); (* print the word and its line nos *)
- IF least <> hold THEN (* make sure entry won't get printed*)
- table[least].key := table[hold].key;
- table[least].first := table[hold].first;
- table[least].last := table[hold].last
- END;
- hold := table[hold].follow (* move to the next entry *)
- END
- END printtable;
-
-
- BEGIN (* ***MAIN PROCEDURE*** *)
-
- current := 0; (* initialize *)
- top := prime;
- tablefull := FALSE;
- FOR i := 1 TO wordlen DO
- free[i] := blank
- END;
- OpenInput(filetype); (* request filename and open file *)
- IF NOT Done THEN (* if file does not exist quit *)
- WriteString("Error--file DK.file.TEXT does not exist")
- ELSE (* otherwise continue *)
- FOR i := 1 TO prime DO (* more initialization *)
- table[i].key := free
- END;
- Read(ch); (* get the first character *)
- WHILE NOT tablefull DO (* do while table is not full *)
- WHILE Done DO (* do while end of file not reached*)
- IF current = maxline THEN (* counter exceeds allowed line no *)
- current := 0 (* reset counter *)
- END;
- INC(current);
- WriteCard(current,digpernum); (* write current line no to screen *)
- Write(blank);
- WHILE (ch <> eol) & (Done) DO (* while not at end of file line *) id := free;
- IF (CAP(ch)>= "A") & (CAP(ch)<="Z") THEN (* see if alphabetic *)
- idcntr := 0;
- REPEAT (* get the word and put in id *)
- IF idcntr < wordlen THEN
- INC(idcntr);
- id[idcntr] := ch;
- END;
- Write(ch);
- Read(ch);
- UNTIL ((CAP(ch)<"A") OR (CAP(ch)>"Z")) & ((ch<"0") OR (ch>"9"));
- tablefull := search() (* call search to add to table *)
- ELSE (* if not a word *)
- IF ch = quote THEN (* if a quote ignore between quotes*)
- REPEAT
- Write(ch);
- Read(ch)
- UNTIL ch = quote
- ELSIF ch = "{" THEN (* if a brace ignore between braces*)
- REPEAT
- Write(ch);
- Read(ch)
- UNTIL ch = "}"
- END;
- Write(ch);
- Read(ch);
- END; (* end if alphabetic statement *)
- END; (* end while not eol loop *)
- WriteLn;
- Read(ch);
- END; (* end while not eof loop *)
- tablefull := TRUE; (* exit outer loop so can print tab*)
- END;
- CloseInput; (* close the input file *)
- (* Write(ff) *)
- printtable; (* print the table *)
- END
- END crossref.
-